package com.siashan.toolkit.oss.qcloud.core;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest;
import com.qcloud.cos.model.PutObjectResult;
import com.qcloud.cos.region.Region;
import com.siashan.toolkit.oss.core.OssResult;
import com.siashan.toolkit.oss.core.OssStorageService;
import com.siashan.toolkit.oss.core.enums.OssChannel;
import com.siashan.toolkit.oss.core.exception.ToolkitOssException;
import org.apache.commons.io.IOUtils;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * 腾讯云存储
 *
 * @author siashan
 * @since v1.0.1
 */
public class QCloudOssStorageService extends OssStorageService {


    private static final String SLASH = "/";

    /**
     * 参数code
     */
    private static final String PARAM_CODE = "code";
    /**
     * 参数message
     */
    private static final String PARAM_MESSAGE = "message";


    /**
     * 腾讯云OSS客户端
     */
    private COSClient client;
    /**
     * 腾讯云配置
     */
    private QcloudOssConfig config;

    /**
     * Jackson系列化
     */
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 构造函数
     */
    public QCloudOssStorageService() {
        config = new QcloudOssConfig();
        config.setAppId(QCloudOssConfiguration.getAppId());
        config.setBucketName(QCloudOssConfiguration.getBucketName());
        config.setDomain(QCloudOssConfiguration.getDomain());
        config.setPrefix(QCloudOssConfiguration.getPrefix());
        config.setRegion(QCloudOssConfiguration.getRegion());
        config.setSecretId(QCloudOssConfiguration.getSecretId());
        config.setSecretKey(QCloudOssConfiguration.getSecretKey());
        init();
    }

    /**
     * 构造函数
     *
     * @param config 腾讯云配置
     */
    public QCloudOssStorageService(QcloudOssConfig config) {
        this.config = config;
        init();
    }

    /**
     * 初始化客户端
     */
    private void init() {
        COSCredentials credentials = new BasicCOSCredentials(config.getSecretId(), config.getSecretKey());

        //初始化客户端配置
        ClientConfig clientConfig = new ClientConfig();
        Region region = new Region(config.getRegion());
        //设置bucket所在的区域，华南：gz 华北：tj 华东：sh
        clientConfig.setRegion(region);

        client = new COSClient(credentials, clientConfig);
    }

    /**
     * 文件上传
     *
     * @param data 文件字节数组
     * @param path 文件路径，包含文件名
     * @return Oss上传结果
     */
    @Override
    public OssResult upload(byte[] data, String path) {
        //腾讯云必需要以"/"开头
        if (!path.startsWith(SLASH)) {
            path = SLASH + path;
        }
        InputStream inputStream = new ByteArrayInputStream(data);
        ObjectMetadata objectMetadata = new ObjectMetadata();
        int inputStreamLength = 0;
        try {
            inputStreamLength = inputStream.available();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // 上传的流如果能够获取准确的流长度，则推荐一定填写 content-length
        // 如果确实没办法获取到，则下面这行可以省略，但同时高级接口也没办法使用分块上传了
        objectMetadata.setContentLength(inputStreamLength);
        //上传到腾讯云
        PutObjectRequest request = new PutObjectRequest(config.getBucketName(), path, inputStream, objectMetadata);
        try {
            PutObjectResult putObjectResult = client.putObject(request);
        } catch (Exception e) {
            throw new ToolkitOssException("上传文件失败", e);
        }
        return OssResult.build(path, config.getDomain(), OssChannel.QCLOUD);
    }

    /**
     * 文件上传
     *
     * @param inputStream 字节流
     * @param path        文件路径，包含文件名
     * @return Oss上传结果
     */
    @Override
    public OssResult upload(InputStream inputStream, String path) {
        try {
            byte[] data = IOUtils.toByteArray(inputStream);
            return this.upload(data, path);
        } catch (IOException e) {
            throw new ToolkitOssException("上传文件失败", e);
        }
    }

    /**
     * 文件上传
     *
     * @param data   文件字节数组
     * @param suffix 后缀
     * @return Oss上传结果
     */
    @Override
    public OssResult uploadSuffix(byte[] data, String suffix) {
        return upload(data, getPath(config.getPrefix(), suffix));
    }

    /**
     * 文件上传
     *
     * @param inputStream 字节流
     * @param suffix      后缀
     * @return Oss上传结果
     */
    @Override
    public OssResult uploadSuffix(InputStream inputStream, String suffix) {
        return upload(inputStream, getPath(config.getPrefix(), suffix));
    }

    /**
     * 文件删除
     *
     * @param fileName 资源名称
     * @return 是否成功标识
     * @since 1.0.2
     */
    @Override
    public boolean remove(String fileName) {
        //腾讯云必需要以"/"开头
        if (!fileName.startsWith(SLASH)) {
            fileName = SLASH + fileName;
        }
        try {
            // 删除单个对象
            client.deleteObject(
                    config.getBucketName(),
                    fileName);
        } catch (CosClientException e) {
            throw new RuntimeException("文件删除失败", e);
        }
        return false;
    }
}
